///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2007-2009 ILOG, S.A.
//  All Rights Reserved.
//  The following is ILOG Source Code.  No modifications may be made to the  
//  ILOG Source Code.  Any usage of the ILOG Source Code is subject to 
//  the terms and conditions of the ILOG End User License Agreement   
//  applicable to this ILOG software product.
//
///////////////////////////////////////////////////////////////////////////////

package ilog.gauges.circular.renderers
{
  import flash.display.Graphics;
  import flash.geom.Point;
  import flash.geom.Rectangle;
  
  import ilog.gauges.gaugesClasses.circular.CircularGaugeElement;
  import ilog.utils.CSSUtil;
  
  import mx.charts.chartClasses.GraphicsUtilities;
  import mx.graphics.GradientEntry;
  import mx.graphics.IFill;
  import mx.graphics.RadialGradient;
  import mx.graphics.Stroke;
  import mx.styles.CSSStyleDeclaration;

  /**
   * Specifies the stroke for the renderer.
   * This style must be an instance of an implementation of the <code>IStroke</code> interface.
   * 
   * @default undefined 
   */
  [Style(name="stroke", type="mx.graphics.IStroke", inherit="no")]

  /**
   * Specifies the fill for the renderer.
   * This style must be an instance of an implementation of the <code>IFill</code> interface.
   *
   * The default value is a radial gradient.
   */
  [Style(name="fill", type="mx.graphics.IFill", inherit="no")]

  /**
   *  A basic semicircle renderer to use in circular gauges. You can customize 
   *  the fill and stroke of this visual element. Inherited radius and origin 
   *  properties are used for drawing.
   *  It can be used for the gauges background.  
   *  
   *  @mxml
   *  
   *  <p>The <code>&lt;ilog:SemiCircleRenderer&gt;</code> tag inherits all the properties
   *  of its parent classes and adds the following properties:</p>
   *  
   *  <pre>
   *  &lt;ilog:SemiCircleRenderer
   *    <strong>Styles</strong>
   *    fill="IFill; a grey-style radial gradient"
   *    stroke="IStroke; no default"
   *  /&gt;
   *  </pre>
   * @includeExample examples/SemiCircleRendererExample.mxml -noswf 
   */  
  public class SemiCircleRenderer extends CircularGaugeElement
  {
    
    /**
     *  Constructor
     */    
    public function SemiCircleRenderer()
    {
      super();
    }
    
    /**
     *  @private
     */
    private static var stylesInited:Boolean = initStyles(); 

    /**
     *  @private
     */
    private static function initStyles():Boolean
    {
      var pStyle:CSSStyleDeclaration =
        CSSUtil.createSelector("SemiCircleRenderer");   
            
      pStyle.defaultFactory = function():void
        {
          var fill:RadialGradient = new RadialGradient();
          
          var g1:GradientEntry = new GradientEntry(0xEEEEEE, 0.0, 1);
          var g2:GradientEntry = new GradientEntry(0xFFFFFF, 0.4, 1);
          var g3:GradientEntry = new GradientEntry(0xCCCCCC, 0.8, 1);
          
          fill.entries = [ g1, g2, g3 ];
          fill.angle = 45;
          fill.focalPointRatio = -0.0;

          this.fill = fill;
          
        }

      return true;
    }

    /**
     *  @private
     */
    private var _cornerRadius:Number = NaN;

    [Bindable("cornerRadiusChanged")]
    [Inspectable(category="Gauge")]
    [PercentProxy("percentCornerRadius")]

    /**
     * Number that specifies the radius of the corner.
     *
     * <p><strong>Note:</strong> You can specify a percentage value in the MXML
     * <code>cornerRadius</code> attribute, such as <code>cornerRadius="10%"</code>,
     * but you cannot use a percentage value in the <code>cornerRadius</code>
     * property in ActionScript.
     * Use the <code>percentCornerRadius</code> property instead.</p>
     * 
     * @default NaN
     * 
     */
    public function get cornerRadius():Number
    {
      return _cornerRadius;
    }

    /**
     *  @private
     */
    public function set cornerRadius(value:Number):void
    {
      _cornerRadius = value;
      if (! isNaN(value))
        _percentCornerRadius = NaN;      
      invalidateDisplayList();      
    }

    /**
     *  @private
     */
    private var _percentCornerRadius:Number = 5;

    [Bindable("resize")]
    [Inspectable(environment="none")]

    /**
     * Number that specifies the corner radius as a percentage
     * of the element's radius.
     *  
     * @default 5
     * 
     */
    public function get percentCornerRadius():Number
    {
      return _percentCornerRadius;
    }

    /**
     *  @private
     */
    public function set percentCornerRadius(value:Number):void
    {
      _percentCornerRadius = value;
      if (! isNaN(value))
        _cornerRadius = NaN;      
      invalidateDisplayList();
    }

    private function getCornerRadius():Number
    {
      if (! isNaN(cornerRadius))
        return cornerRadius;
      else return getRadius() * percentCornerRadius / 100;
    }
    
    /**
     *  @private
     */    
    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
      super.updateDisplayList(unscaledWidth, unscaledHeight);
      var g:Graphics = graphics;
      var o:Point = getOrigin();
      var r:Number = getRadius();
      var fill:IFill = CSSUtil.fillFromStyle(getStyle("fill"));
      var stroke:Stroke = getStyle("stroke");

      g.clear();
      if (stroke)
        stroke.apply(g);
      
      if (fill)
      {
        var m:Number = Math.min(unscaledWidth, unscaledHeight);
        fill.begin(g, new Rectangle(0, 0, unscaledWidth, unscaledHeight));        
      }
      
      GraphicsUtilities.drawArc(graphics,o.x, o.y, 0, Math.PI, r);
      var cr:Number = getCornerRadius();
      var o2x:Number = o.x - r + cr;
      var o3x:Number = o.x + r - cr;

      GraphicsUtilities.drawArc(graphics, o2x, o.y, Math.PI, Math.PI/2, cr, NaN, true);
      graphics.lineTo(o3x, o.y + cr);
      GraphicsUtilities.drawArc(graphics, o3x, o.y, 1.5*Math.PI, Math.PI/2, cr, NaN, true);
      graphics.endFill();  
    }

    /**
     *  @private
     */       
    override protected function measure():void
    {
      super.measure();
      if (measuredWidth == 0 ||
          isNaN(cornerRadius))
      {
        measuredMinWidth = measuredMinHeight = measuredWidth = measuredHeight = 0;        
      }
      else
      {
        measuredMinWidth = measuredWidth = originX + radius; 
        measuredMinHeight = measuredHeight = originY + cornerRadius;
      }
    }
  }
}
